//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#define __NO_LINKNODE_CONSTRUCTOR
#include "cgmodule.h"
#include "ntimage.h"
#include "cfile.h"
#include "pub.h"
#include "win32module.h"
#include <string.h>

typedef struct PeInfo {
    Aura_UInt32        uImageBase;
    Aura_UInt32        uEntryPoint;
    Aura_UInt32        cSections;
    Aura_UInt32        uTotalSize;

    Aura_UInt32        uExportRVA;
    Aura_UInt32        uExportSize;
    Aura_UInt32        uImportRVA;
    Aura_UInt32        uImportSize;
    Aura_UInt32        uResourceRVA;
    Aura_UInt32        uResourceSize;

    Aura_UInt32        uRelocOffset;
    Aura_UInt32        uRelocSize;
    Aura_UInt32        uDebugInfoRVA;

    Aura_UInt32        uSecHeaderOffset;
}PeInfo;

Aura_Handle  s_hModuleLock;
Aura_Handle  g_hAttachLock;

DLinkNode s_ModuleList = {&s_ModuleList, &s_ModuleList};

#define PATH_MAX	(259)
#define MIN_BUFFER_SIZE 0x1000
#define MIN(a, b)      (((a) < (b))? (a) : (b))
#define FALL_INTO(addr, base, size) \
    ((addr) >= (base) && (addr) < (base) + (size))

GModule * FindModuleByName(const Aura_PWChar wszName);
GModule * FindModuleByImageBase(Aura_UInt32 uImageBase);

Aura_ECode FixupImport(GModule *pModule, Aura_UInt32 uImageBase);
Aura_ECode FixupExport(GModule * pModule, Aura_UInt32 uImageBase);

Aura_ECode RelocPeModule(GModule * pModule,
        Aura_UInt32 uOffset,
        Aura_UInt32 uRelocOffset);

void AnsiToUnic(wchar_t *pwszName, const char *pszName);


Aura_ECode ParsePeHeader(
        CLoadedFile *pFile, ModuleFileType modFileType,
        PeInfo * pInfo)
{
    PIMAGE_DOS_HEADER pDosHeader = AURA_NULL;
    PIMAGE_FILE_HEADER pFileHeader = AURA_NULL;
    PIMAGE_OPTIONAL_HEADER pOptHeader = AURA_NULL;
    PIMAGE_NT_HEADERS pNTHeader = AURA_NULL;
    Aura_ECode ec = AURA_NOERROR;
    LONG lNewHeaderOffset;
    Aura_UInt32 uSize = pFile->GetSize();

    // Verify DOS and PE magic number
    //
    if (uSize < sizeof(IMAGE_DOS_HEADER)) {
        Aura_printf("Not PE file. FILE:%s, LINE:%d\n", __FILE__, __LINE__);
        return AURA_E_BAD_FILE_FORMAT;
    }
    ec = pFile->Read(0, sizeof(IMAGE_DOS_HEADER),
                               (Aura_PVoid*)&pDosHeader);
    if (AURA_FAILED(ec))
        goto ErrorExit;

    if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE
        || pDosHeader->e_lfanew < 0
        || (Aura_UInt32)pDosHeader->e_lfanew > uSize
        || (sizeof(IMAGE_NT_HEADERS) + (Aura_UInt32)pDosHeader->e_lfanew)
            > uSize) {
        Aura_printf("Not PE file. FILE:%s, LINE:%d\n", __FILE__, __LINE__);
        ec = AURA_E_BAD_FILE_FORMAT;
        goto ErrorExit;
    }

    lNewHeaderOffset = pDosHeader->e_lfanew;
    ec = pFile->Read(lNewHeaderOffset
            , sizeof(IMAGE_NT_HEADERS), (Aura_PVoid*)&pNTHeader);
    if (AURA_FAILED(ec))
        goto ErrorExit;

    if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) {
        Aura_printf("Not PE file. FILE:%s, LINE:%d\n", __FILE__, __LINE__);
        ec = AURA_E_BAD_FILE_FORMAT;
        goto ErrorExit;
    }

    // Check File-Header
    //
    pFileHeader = &pNTHeader->FileHeader;

#ifdef _x86
    if (pFileHeader->Machine != IMAGE_FILE_MACHINE_I386 &&
        pFileHeader->Machine != IMAGE_FILE_MACHINE_I386 + 1 &&
        pFileHeader->Machine != IMAGE_FILE_MACHINE_I386 + 2)
#elif defined(_arm)
    if (pFileHeader->Machine != IMAGE_FILE_MACHINE_ARM &&
        pFileHeader->Machine != IMAGE_FILE_MACHINE_ARM + 2)
#elif defined(_mips)
    if (pFileHeader->Machine != IMAGE_FILE_MACHINE_R4000)
#else
#error Unknown architecture
#endif
    {
        Aura_printf("Not support the executable file. FILE:%s, LINE:%d\n"
                __FILE__, __LINE__);
        goto ErrorExit;
    }

    if (pFileHeader->SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER)
        || !(pFileHeader->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)
        || (pFileHeader->Characteristics & ModuleFileType_MARK) != modFileType
        ) {
        goto ErrorExit;
    }

    // Check Optional-Header
    //
    pOptHeader = &pNTHeader->OptionalHeader;
    if (pOptHeader->Magic != 0x010b) {
        Aura_printf("*ERROR* Invalid Optional Header of PE file. FILE:%s, LINE:%d\n",
                __FILE__, __LINE__);
        goto ErrorExit;
    }

    //
    // Get summary info of this image.
    //
    pInfo->cSections = pFileHeader->NumberOfSections;
    pInfo->uImageBase = pOptHeader->ImageBase;
    pInfo->uEntryPoint = pOptHeader->AddressOfEntryPoint;
    pInfo->uTotalSize = pOptHeader->SizeOfImage;

    pInfo->uExportRVA = pOptHeader-> \
        DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    pInfo->uExportSize = pOptHeader-> \
        DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
    pInfo->uImportRVA = pOptHeader-> \
        DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    pInfo->uImportSize = pOptHeader-> \
        DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;

    pInfo->uResourceRVA = pOptHeader-> \
        DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
    pInfo->uResourceSize = pOptHeader-> \
        DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size;
    pInfo->uRelocOffset = pOptHeader-> \
        DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
    pInfo->uRelocSize = pOptHeader-> \
        DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;

    pInfo->uSecHeaderOffset = lNewHeaderOffset + sizeof(IMAGE_NT_HEADERS);

    pInfo->uDebugInfoRVA = pOptHeader-> \
        DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;

    ec = AURA_NOERROR;

ErrorExit:
    return ec;
}


Aura_ECode LoadPeSections(CLoadedFile *pFile, PeInfo * pInfo, GModule *pModule)
{
    register PIMAGE_SECTION_HEADER pSecHeader;
    Aura_Byte  * pSecHeaderData;
    Aura_ECode ec = AURA_NOERROR;

//    Aura_printf("pInfo->cSections = %d \n", pInfo->cSections); // the number of sections

    pModule->m_cSections = pInfo->cSections;
    pModule->m_pSections = new Section[pModule->m_cSections];
    memset(pModule->m_pSections, 0, (sizeof(Section) * pModule->m_cSections));

    for (Aura_UInt32 i = 0; i < pModule->m_cSections; i++) {
        pModule->m_pSections[i].Initialize();
    }

    pSecHeaderData = (Aura_Byte *)Aura_malloc(pInfo->cSections
            * sizeof(IMAGE_SECTION_HEADER));
    if(!pSecHeaderData) {
        return AURA_E_OUT_OF_MEMORY;
    }

    ec = pFile->Read(pInfo->uSecHeaderOffset,
            pInfo->cSections * sizeof(IMAGE_SECTION_HEADER),
            (Aura_PVoid*)&pSecHeaderData, AURA_FALSE);
    if (AURA_FAILED(ec)) {
        Aura_printf("Error: read section header failed! file:%s. line:%d.\n", __FILE__, __LINE__);
        Aura_free(pSecHeaderData);
        return ec;
    }

    pSecHeader = (PIMAGE_SECTION_HEADER)pSecHeaderData;

    Aura_UInt32 n;
    for (n = 0; n < pModule->m_cSections; n++) {
        memcpy(pModule->m_pSections[n].m_szName, pSecHeader->Name, 8);

        pModule->m_pSections[n].SetImageBase(pModule->m_uImageBase);
        pModule->m_pSections[n].SetAddr(pSecHeader->VirtualAddress);
        pModule->m_pSections[n].SetSize(pSecHeader->Misc.VirtualSize);


        if (pSecHeader->Characteristics & IMAGE_SCN_MEM_READ) {
            pModule->m_pSections[n].m_uProtect |= Aura_MemoryProtection_Read;
        }

        if (pSecHeader->Characteristics & IMAGE_SCN_MEM_WRITE) {
            pModule->m_pSections[n].m_uProtect |= Aura_MemoryProtection_Write;
        }

        if (pSecHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
            pModule->m_pSections[n].m_uProtect |= Aura_MemoryProtection_Exec;
        }

        //
        // Check current section, if it's an especial section such as
        // relocation, export, import or resource, we need record it's info
        // in module.
        //
//        if (pSecHeader->VirtualAddress == pInfo->uRelocOffset) {
//            pInfo->uRelocOffset = pSecHeader->PointerToRawData;
//        }

        if (FALL_INTO(pInfo->uResourceRVA,
            pSecHeader->VirtualAddress, pSecHeader->Misc.VirtualSize)) {
            pModule->m_pResource = &(pModule->m_pSections[n]);
            pModule->m_pSections[n].m_uProtect &= ~Aura_MemoryProtection_Write;
        }

        // The export table and import table maybe local in the same section.
        else {
            if (FALL_INTO(pInfo->uExportRVA,
                pSecHeader->VirtualAddress, pSecHeader->Misc.VirtualSize)) {
                assert(AURA_NULL == pModule->m_pExport);
                pModule->m_pExport = &(pModule->m_pSections[n]);
                pModule->m_uExportOffset =
                    pInfo->uExportRVA - pSecHeader->VirtualAddress;

                pModule->m_uExportSize = pInfo->uExportSize;

                // Clear writeable flag to save memory AND catch invalid pointer.
                pModule->m_pSections[n].m_uProtect &= ~Aura_MemoryProtection_Write;
            }

            if (FALL_INTO(pInfo->uImportRVA,
                pSecHeader->VirtualAddress, pSecHeader->Misc.VirtualSize)) {
                assert(AURA_NULL == pModule->m_pImport);
                pModule->m_pImport = &(pModule->m_pSections[n]);
                pModule->m_uImportOffset =
                    pInfo->uImportRVA - pSecHeader->VirtualAddress;
                pModule->m_uImportSize = pInfo->uImportSize;
                // Clear writeable flag to save memory AND catch invalid pointer.
                pModule->m_pSections[n].m_uProtect &= ~Aura_MemoryProtection_Write;
            }
        }

        //
        // Initialize the content of the section.
        //
        pModule->m_pSections[n].MemZero();
        if (pSecHeader->PointerToRawData && pSecHeader->SizeOfRawData) {
            Aura_UInt32 uLmt = pSecHeader->SizeOfRawData;
            Aura_UInt32 uOff = 0;

            while (uOff < uLmt) {
                Aura_Byte *pRawData;

                Aura_UInt32 uRead = MIN(MIN_BUFFER_SIZE, uLmt - uOff);

                ec = pFile->Read(pSecHeader->PointerToRawData + uOff,
                                 uRead, (Aura_PVoid*)&pRawData);
                if (AURA_FAILED(ec)) {
                     goto EXIT;
                }

                pModule->m_pSections[n].MemCopy(uOff, uRead, pRawData);
                uOff += uRead;
            }

            assert(uOff == uLmt);
        }

        pSecHeader++;
    }

EXIT:
    Aura_free(pSecHeaderData);
    return 0;
}

void DumpPeInfo(PeInfo *pInfo)
{
    Aura_printf("pInfo->uImageBase:        0x%x. \n", pInfo->uImageBase);
    Aura_printf("pInfo->uEntryPoint:       0x%x. \n", pInfo->uEntryPoint);
    Aura_printf("pInfo->cSections:         0x%x. \n", pInfo->cSections);
    Aura_printf("pInfo->uTotalSize:        0x%x. \n", pInfo->uTotalSize);
    Aura_printf("pInfo->uExportRVA:        0x%x. \n", pInfo->uExportRVA);
    Aura_printf("pInfo->uExportSize:       0x%x. \n", pInfo->uExportSize);
    Aura_printf("pInfo->uImportRVA:        0x%x. \n", pInfo->uImportRVA);
    Aura_printf("pInfo->uImportSize:       0x%x. \n", pInfo->uImportSize);
    Aura_printf("pInfo->uResourceRVA:      0x%x. \n", pInfo->uResourceRVA);
    Aura_printf("pInfo->uResourceSize:     0x%x. \n", pInfo->uResourceSize);
    Aura_printf("pInfo->uRelocOffset:      0x%x. \n", pInfo->uRelocOffset);
    Aura_printf("pInfo->uRelocSize:        0x%x. \n", pInfo->uRelocSize);
    Aura_printf("pInfo->uDebugInfoRVA:     0x%x. \n", pInfo->uDebugInfoRVA);
    Aura_printf("pInfo->uSecHeaderOffset:  0x%x. \n", pInfo->uSecHeaderOffset);
}

#ifdef _GNUC
/*************************for gdbserver***begin*****************************/
struct DbgData{
    Aura_PWChar m_pwszName;
    long     m_lTextAdd;
    long     m_lDataAdd;
    long     m_lBssAdd;
};

static void GetDbgData(GModule * pModule, DbgData *pDbgData)
{
    unsigned int i;
    Section *pSections;

    pDbgData->m_pwszName
        = Aura_wcsrchr(pModule->m_wszFullPath, '\\') + 1;

    pDbgData->m_lTextAdd = 0;
    pDbgData->m_lDataAdd = 0;
    pDbgData->m_lBssAdd  = 0;

    for(i = 0; i < pModule->m_cSections; i++){
        pSections = &pModule->m_pSections[i];
        if(0 == strcmp(".text", pSections->m_szName)){
            pDbgData->m_lTextAdd  = (long)(pModule->m_uImageBase
                + pSections->m_uVAddr);
        }
        if(0 == strcmp(".data", pSections->m_szName)){
            pDbgData->m_lDataAdd = (long)(pModule->m_uImageBase
                + pSections->m_uVAddr);
        }
        if(0 == strcmp(".bss", pSections->m_szName)){
            pDbgData->m_lBssAdd = (long)(pModule->m_uImageBase
                + pSections->m_uVAddr);
        }
        if((0 != pDbgData->m_lTextAdd)
         &&(0 != pDbgData->m_lDataAdd)
         &&(0 != pDbgData->m_lBssAdd)){
            break;
        }
    }
}

Aura_ECode SendByPipe(int len, char *pBuf)
{
    Aura_ChannelId id0 = NULL;
    Aura_ChannelId id1 = NULL;
    Aura_ECode ec;

    ec = AuraIpcChannel_Create((Aura_PWChar)L"elauradbg_pipe", &id0);
    if (AURA_NOERROR != ec) {
        Aura_printf(">>>pipe create error. \n");
        goto ErrorExit;
    }

    ec = AuraIpcChannel_WaitForConnection((Aura_PWChar)L"elauradbg_pipe", &id0, &id1);
    if (AURA_NOERROR != ec) {
        Aura_printf(">>>pipe wait connect error. \n");
        goto ErrorExit;
    }

    ec = AuraIpcChannel_AsyncWrite(id1, pBuf, len);
    if (AURA_NOERROR != ec) {
        Aura_printf(">>>pipe write error. \n");
        goto ErrorExit;
    }

    AuraIpcChannel_Destroy(id1);
    AuraIpcChannel_Destroy(id0);
    return ec;
ErrorExit:
    if (NULL != id1)
        AuraIpcChannel_Destroy(id1);
    if (NULL != id0)
        AuraIpcChannel_Destroy(id0);
    return ec;
}

// FORMAT == ***;FILENAME 0x.TEXTADD -s .data 0x.DATAADD -s .bss 0x.BSSADD;
Aura_ECode SendDllDbgData(GModule * pModule)
{
    DbgData data;
    char pSendBuf[256];

    GetDbgData(pModule, &data);

    int slen = 4;
    pSendBuf[0] = 1;
    pSendBuf[1] = 1;
    pSendBuf[2] = 1;
    pSendBuf[3] = 1; // to fill the first 4 bytes with 1.
    while (*data.m_pwszName) {
        pSendBuf[slen++] = (char)*data.m_pwszName++;
    }

    if(0 != data.m_lTextAdd){
        //slen = strlen(pSendBuf);
        sprintf(&pSendBuf[slen], " 0x%x", data.m_lTextAdd);
    }

    if(0 != data.m_lDataAdd){
        slen = strlen(pSendBuf);
        sprintf(&pSendBuf[slen], " -s .data 0x%x", data.m_lDataAdd);
    }

    if(0 != data.m_lBssAdd){
        slen = strlen(pSendBuf);
        sprintf(&pSendBuf[slen], " -s .bss 0x%x", data.m_lBssAdd);
    }
    strcat(pSendBuf, ";");

    int *p = (int *)(&pSendBuf[0]);
    *p = strlen(pSendBuf) - 4; // to fill the first 4 byte with the data length.
//Aura_printf("++++++++++++++++++++ %s\n", &pSendBuf[4]);
    return SendByPipe(256, pSendBuf);
}
/*************************for gdbserver***end*****************************/
#endif

Aura_ECode LoadPeModule(
        CLoadedFile *pFile,
        Aura_UInt32 dwFlags,
        ModuleFileType  modFileType,
        GModule *pModule)
{
    PeInfo peInfo;
    Aura_ECode ec;

    ec = ParsePeHeader(pFile, modFileType, &peInfo);
    if (AURA_FAILED(ec)) {
        goto ErrorExit;
    }

    if(ModuleFileType_EXE == modFileType) {
        pModule->m_fileType = ModuleFileType_EXE;
    } else {
        pModule->m_fileType = ModuleFileType_DLL;
    }

//    DumpPeInfo(&peInfo);
    if(!pModule->AllocMemery(peInfo.uImageBase, peInfo.uTotalSize)){
        Aura_printf("pModule AllocMemory error. file:%s. line:%d.\n",__FILE__, __LINE__);
        return AURA_E_OUT_OF_MEMORY;
    }

    pModule->m_uTotalSize = peInfo.uTotalSize;
    pModule->m_uEntryPoint = peInfo.uEntryPoint + pModule->m_uImageBase;
    pModule->m_uRelocOffset = pModule->m_uImageBase - peInfo.uImageBase;

    ec = LoadPeSections(pFile, &peInfo, pModule);
    if(AURA_FAILED(ec)) {
        goto ErrorExit;
    }

    if (pModule->m_uRelocOffset && peInfo.uRelocSize) {
        ec = RelocPeModule(
            pModule,
            pModule->m_uRelocOffset,
            peInfo.uRelocOffset);
        if (AURA_NOERROR != ec) {
            Aura_printf("RelocPeModule error. file:%s. line:%d. \n", __FILE__, __LINE__);
            goto ErrorExit;
        }
    }

    if (pModule->m_pExport) {
        ec = FixupExport(pModule, pModule->m_uImageBase);
        if (AURA_NOERROR != ec) {
            Aura_printf("FixupExport error. file:%s. line:%d.\n", __FILE__, __LINE__);
            goto ErrorExit;
        }
    }

    if (pModule->m_pImport) {
        ec = FixupImport(pModule, pModule->m_uImageBase);
        if (AURA_NOERROR != ec) {
            Aura_printf("FixupImport error. file:%s. line:%d.\n", __FILE__, __LINE__);
        }
    }

#ifdef _GNUC
    if(dwFlags == 99) { // debug flag
        ec = SendDllDbgData(pModule);
    }
#endif

ErrorExit:
    return ec;
}

void GUnloadModule(GModule * pModule)
{
    ModuleRef *pModuleRef;
    Win32ModuleRef *pWin32ModuleRef;

    Lock(s_hModuleLock);
    assert (0 == pModule->m_cRef);

    if (pModule->m_wszFullPath) delete pModule->m_wszFullPath;
    if (pModule->m_pSections) delete [] pModule->m_pSections;
    if (pModule->m_uImageBase && pModule->m_uTotalSize) {
        Aura_ECode ec = AuraVirtualMemory_Unmap(pModule->m_uImageBase, pModule->m_uTotalSize);
        if(AURA_FAILED(ec)) {
            Aura_printf("Error unmap module memery failed! file:%s. line:%d.\n", __FILE__, __LINE__);
        }
    }

    while(pModule->m_rModuleList.m_pNext
        != &pModule->m_rModuleList){
        pModuleRef = (ModuleRef *)pModule->m_rModuleList.m_pNext;
        pModuleRef->m_pModule->Release();
        pModuleRef->Detach();
        delete pModuleRef;
    }

    while(pModule->m_win32ModuleList.m_pNext
            != &pModule->m_win32ModuleList){
        pWin32ModuleRef = (Win32ModuleRef *)pModule->m_win32ModuleList.m_pNext;
        Win32Module_Unload(pWin32ModuleRef->m_pWin32Module);
        pWin32ModuleRef->Detach();
        delete pWin32ModuleRef;
    }

    pModule->Detach();
    Unlock(s_hModuleLock);
}

//TODO need enviroment
wchar_t *GetModuleFullPathW(const wchar_t *wszName, wchar_t *wszFullName)
{
    assert(wszName && wszFullName);

    wchar_t *wsbName = NULL;
    wsbName = wcsrchr(wszName, '/');
    if(wsbName) {
        wcscpy(wszFullName, L"L:\\");
        wcscat(wszFullName, ++wsbName);
    } else {
        wcscpy(wszFullName, L"L:\\");
        wcscat(wszFullName, wszName);
    }

    return wszFullName;
}


Aura_ECode GlobalLoadModuleW(
        const Aura_PWChar wszName,
        Aura_UInt32 dwFlags,
        ModuleFileType  modFileType,
        GModule ** ppModule)
{
    GModule *pModule;
    WCHAR pwszFileFullPath[PATH_MAX];

    Aura_ECode ec;

    if(!GetModuleFullPathW((const wchar_t *)wszName, (wchar_t *)pwszFileFullPath)) {
        return AURA_E_INVALID_ARGUMENT;
    }

    CLoadedFile file;
    ec = file.Init((Aura_PWChar)pwszFileFullPath);
    if(AURA_FAILED(ec)) {
        return AURA_E_FILE_NOT_FOUND;
    }

    Aura_UInt32 len = wcslen((const wchar_t *)pwszFileFullPath) + 1;

    Lock(s_hModuleLock);
    *ppModule = FindModuleByName((const Aura_PWChar)pwszFileFullPath);
    if (*ppModule) {
        Unlock(s_hModuleLock);
        return AURA_NOERROR;
    }

    pModule = new GModule;
    if (!pModule) {
        Unlock(s_hModuleLock);
        return AURA_E_OUT_OF_MEMORY;
    }

    pModule->m_wszFullPath = new Aura_WChar[len];
    if (!pModule->m_wszFullPath) {
        delete pModule;
        Unlock(s_hModuleLock);
        return AURA_E_OUT_OF_MEMORY;
    }

    wcscpy((wchar_t*)pModule->m_wszFullPath, (const wchar_t*)pwszFileFullPath);
    ec = LoadPeModule(&file, dwFlags, modFileType, pModule);
    if(AURA_FAILED(ec)){
        goto ErrorExit;
    }

    s_ModuleList.InsertNext(pModule); //
    *ppModule = pModule;
    pModule->AddRef();

    Unlock(s_hModuleLock); //lock
    return ec;

ErrorExit:
    if(pModule) {
        GUnloadModule(pModule);
        delete pModule;
    }
    Unlock(s_hModuleLock);
    return ec;
}


Aura_ECode GlobalLoadModuleA(
        CHAR *szName,
        Aura_UInt32 dwFlags,
        ModuleFileType  modFileType,
        GModule ** ppModule)
{
    Aura_WChar wszName[256] = {0};

    AnsiToUnic((wchar_t *)wszName, szName);

    Aura_ECode ec = GlobalLoadModuleW(wszName, dwFlags, modFileType, ppModule);

    return ec;
}

Aura_ECode CreateModuleLock()
{
    Aura_ECode ec = AuraCriticalSection_Create(&s_hModuleLock);
    if(AURA_FAILED(ec)){
        return ec;
    }

    ec = AuraCriticalSection_Create(&g_hAttachLock);
    return ec;
}

void DestroyModuleLock()
{
    AuraCriticalSection_Destroy(s_hModuleLock);
    AuraCriticalSection_Destroy(g_hAttachLock);
}
